﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace RedmineIssuesProvider
{
    public partial class MainForm : Form
    {
        private Service _service;
        ItemComparer itemComparer = new ItemComparer();

        public static void FillComboBox<T>(T list, ComboBox cb)
        {
            cb.Items.Clear();
            foreach (var enumeration in (IEnumerable)list)
            {
                cb.Items.Add(enumeration);
            }
            if (cb.Items.Count > 0)
                cb.SelectedIndex = 0;
        }

        #region ShowHide* methods

        private void chbDueDate_CheckedChanged(object sender, EventArgs e)
        {
            ShowHideDueDate();
        }

        private void chbStatus_CheckedChanged(object sender, EventArgs e)
        {
            ShowHideStatus();
        }

        private void chbAuthor_CheckedChanged(object sender, EventArgs e)
        {
            ShowHideAuthor();
        }

        private void chbPriority_CheckedChanged(object sender, EventArgs e)
        {
            ShowHidePriority();
        }

        private void chbTracker_CheckedChanged(object sender, EventArgs e)
        {
            ShowHideTracker();
        }

        private void chbAssigned_CheckedChanged(object sender, EventArgs e)
        {
            ShowHideAssigned();
        }

        private void ShowHideFilter()
        {
            ShowHideAssigned();
            ShowHideAuthor();
            ShowHideDueDate();
            ShowHidePriority();
            ShowHideStatus();
            ShowHideTracker();
        }

        private void ShowHideDueDate()
        {
            bool show = chbDueDate.Checked;

            cbDueDateCondition.Enabled = show;
            tbDays.Enabled = show;
            lDays.Enabled = show;
            if (show)
            {
                ShowHideDays();
            }
        }

        private void ShowHideStatus()
        {
            bool show = chbStatus.Checked;

            cbStatusCondition.Enabled = show;
            cbStatus.Enabled = show;
            if (show)
            {
                ShowHideStatusList();
            }
        }

        private void ShowHidePriority()
        {
            bool show = chbPriority.Checked;

            cbPriorityCondition.Enabled = show;
            cbPriority.Enabled = show;
        }

        private void ShowHideTracker()
        {
            bool show = chbTracker.Checked;

            cbTrackerCondition.Enabled = show;
            cbTracker.Enabled = show;
        }

        private void ShowHideAuthor()
        {
            bool show = chbAuthor.Checked;

            cbAuthorCondition.Enabled = show;
            cbAuthor.Enabled = show;
        }

        private void ShowHideAssigned()
        {
            bool show = chbAssigned.Checked;
            cbAssignedCondition.Enabled = show;
            cbAssigned.Enabled = show;
            if (show)
            {
                ShowHideAssignedList();
            }
        }

        private void ShowHideStatusList()
        {
            cbStatus.Enabled = ((OpenClosed)cbStatusCondition.SelectedItem == OpenClosed.Equal || (OpenClosed)cbStatusCondition.SelectedItem == OpenClosed.NotEqual);
        }

        private void ShowHideAssignedList()
        {
            cbAssigned.Enabled = ((AssignedCondition)cbAssignedCondition.SelectedItem == AssignedCondition.Equal || (AssignedCondition)cbAssignedCondition.SelectedItem == AssignedCondition.NotEqual);
        }

        private void ShowHideDays()
        {
            bool show = ((DueDateCondition)cbDueDateCondition.SelectedItem != DueDateCondition.Today && (DueDateCondition)cbDueDateCondition.SelectedItem != DueDateCondition.ThisWeek);

            tbDays.Enabled = show;
            lDays.Enabled = show;
        }

        #endregion

        private void UpdateStatus()
        {
            tsIssues.Text = "Всего задач: "+listView1.Items.Count.ToString()+"; Отмечено задач: "+listView1.CheckedItems.Count.ToString();
        }

        private void FillListView(IEnumerable<Issue> list)
        {
            listView1.Items.Clear();

            bool odd = true;

            tsProgress.Maximum = list.Count();
            tsProgress.Visible = true;
            //listView1.BeginUpdate();

            foreach (Issue issue in list)
            {
                var newItem = new ListViewItem();
                newItem.Tag = issue;
                newItem.BackColor = issue.GetColor(odd);
                if (issue.Closed())
                {
                    newItem.Font = new Font(newItem.Font, FontStyle.Strikeout);
                    newItem.ForeColor = Color.LightGray;
                }

                newItem.SubItems.Add(issue.id.ToString());
                newItem.SubItems.Add(issue.tracker.name);
                newItem.SubItems.Add(issue.subject);
                newItem.SubItems.Add(issue.author.name);
                if (issue.assigned_to != null)
                    newItem.SubItems.Add(issue.assigned_to.name);
                else
                    newItem.SubItems.Add("");
                newItem.SubItems.Add(issue.due_date.ToShortDateString());
                listView1.Items.Add(newItem);

                odd = !odd;

                tsProgress.PerformStep();
            }

            tsProgress.Visible = false;
            //listView1.EndUpdate();
            UpdateStatus();
        }

        public MainForm(Service service)
        {
            InitializeComponent();
            if (service == null)
            {
                _service = new Service();
            }
            else
                _service = service;

            FillComboBox(_service.Projects,cbProject);
            cbProject.SelectedItem = _service.Projects.Find(x => (x.id == Properties.Settings.Default.DefaultProject));

            FillComboBox(_service.Trackers,cbTracker);
            FillComboBox(_service.Priorities,cbPriority);
            FillComboBox(_service.Users,cbAuthor);
            FillComboBox(_service.Users, cbAssigned);
            FillComboBox(_service.IssueStatuses,cbStatus);

            cbTrackerCondition.DataSource = Enum.GetValues(typeof (EqualNotEqual));
            cbStatusCondition.DataSource = Enum.GetValues(typeof (OpenClosed));
            cbPriorityCondition.DataSource = Enum.GetValues(typeof (EqualNotEqual));
            cbAuthorCondition.DataSource = Enum.GetValues(typeof (EqualNotEqual));
            cbAssignedCondition.DataSource = Enum.GetValues(typeof(AssignedCondition));
            cbDueDateCondition.DataSource = Enum.GetValues(typeof (DueDateCondition));
            
            listView1.ListViewItemSorter = itemComparer;

            LoadFilters();

            btnSave.Enabled = _service.FiltersExist;

            if (_service.FiltersExist && cbFilters.SelectedIndex >= 0)
            {
                LoadIssues();
            }
        }

        #region Работа с фильтрами

        private void LoadFilters()
        {
            FillComboBox(_service.Filters.Content, cbFilters);
            cbFilters.SelectedItem =
                _service.Filters.Content.Find(x => (x.name == Properties.Settings.Default.DefaultFilter));

            ShowHideFilter();
        }

        private void GetCurrentFilter(ref Filter filter)
        {
            if (chbStatus.Checked)
                filter.SetStatus((OpenClosed)cbStatusCondition.SelectedItem,(IssueStatus)cbStatus.SelectedItem);
            if (chbTracker.Checked)
                filter.SetTracker((EqualNotEqual)cbTrackerCondition.SelectedItem, (Tracker)cbTracker.SelectedItem);
            if (chbPriority.Checked)
                filter.SetPriority((EqualNotEqual)cbPriorityCondition.SelectedItem, (Priority)cbPriority.SelectedItem);
            if (chbAuthor.Checked)
                filter.SetAuthor((EqualNotEqual)cbAuthorCondition.SelectedItem, (User)cbAuthor.SelectedItem);
            if (chbAssigned.Checked)
                filter.SetAssigned((AssignedCondition)cbAssignedCondition.SelectedItem, (User)cbAssigned.SelectedItem);
            if (chbDueDate.Checked)
                filter.SetDueDate((DueDateCondition)cbDueDateCondition.SelectedItem, (int)tbDays.Value);
        }

        private void SetFilter(Filter filter)
        {
            if (filter != null)
            {
                Priority foundedPriority = new Priority();
                if (filter.priority != null)
                    foundedPriority = _service.Priorities.Find(x => (x.id == filter.priority.id));
                chbPriority.Checked = filter.priorityChecked;
                cbPriorityCondition.SelectedItem = filter.priorityCondition;
                cbPriority.SelectedItem = foundedPriority;

                IssueStatus foundedIssueStatus = new IssueStatus();
                if (filter.status != null)
                    foundedIssueStatus = _service.IssueStatuses.Find(x => (x.id == filter.status.id));
                chbStatus.Checked = filter.statusChecked;
                cbStatusCondition.SelectedItem = filter.statusCondition;
                cbStatus.SelectedItem = foundedIssueStatus;

                Tracker foundedTracker = new Tracker();
                if (filter.tracker != null)
                    foundedTracker = _service.Trackers.Find(x => (x.id == filter.tracker.id));
                chbTracker.Checked = filter.trackerChecked;
                cbTrackerCondition.SelectedItem = filter.trackerCondition;
                cbTracker.SelectedItem = foundedTracker;

                User foundedUser = new User();
                if (filter.author != null)
                    foundedUser = _service.Users.Find(x => (x.id == filter.author.id));
                chbAuthor.Checked = filter.authorChecked;
                cbAuthorCondition.SelectedItem = filter.authorCondition;
                cbTracker.SelectedItem = foundedUser;

                if (filter.assigned != null)
                    foundedUser = _service.Users.Find(x => (x.id == filter.assigned.id));
                chbAssigned.Checked = filter.assignedChecked;
                cbAssignedCondition.SelectedItem = filter.assignedCondition;
                cbAssigned.SelectedItem = foundedUser;

                chbDueDate.Checked = filter.dueDateChecked;
                cbDueDateCondition.SelectedItem = filter.dueDateCondition;
                tbDays.Text = filter.Days.ToString();
            }
            else
            {
                chbPriority.Checked = false;
                chbStatus.Checked = false;
                chbTracker.Checked = false;
                chbAuthor.Checked = false;
                chbAssigned.Checked = false;
                chbDueDate.Checked = false;
            }

            ShowHideFilter();
        }

        #endregion

        private void button1_Click(object sender, EventArgs e)
        {
            LoadIssues();
        }

        private void LoadIssues()
        {
            _service.FillIssues();
            Filter filter = new Filter {name = "current filter"};
            GetCurrentFilter(ref filter);
            var list = _service.FilterIssues(filter, DateTime.Today);
            FillListView(list);
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            _service.CurrentProject = (Project) cbProject.SelectedItem;
        }

        private void listView1_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            itemComparer.ColumnIndex = e.Column;
            listView1.Sort();
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            DialogResult = System.Windows.Forms.DialogResult.OK;
        }

        private void listView1_ItemChecked(object sender, ItemCheckedEventArgs e)
        {
            ((Issue) e.Item.Tag).Checked = e.Item.Checked;
            UpdateStatus();
        }

        private void cbStatusCondition_SelectedIndexChanged(object sender, EventArgs e)
        {
            ShowHideStatusList();
        }

        private void cbTrackerCondition_SelectedIndexChanged(object sender, EventArgs e)
        {
            
        }

        private void cbAssignedCondition_SelectedIndexChanged(object sender, EventArgs e)
        {
            ShowHideAssignedList();
        }

        private void cbDueDateCondition_SelectedIndexChanged(object sender, EventArgs e)
        {
            ShowHideDays();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (_service.FiltersExist)
            {
                Filter currentFilter = _service.Filters.Content.Find(x => (x.name == cbFilters.Text));
                if (currentFilter == null)
                {
                    currentFilter = new Filter();
                    currentFilter.name = cbFilters.Text;
                    _service.Filters.Content.Add(currentFilter);
                    cbFilters.Items.Add(currentFilter);
                }

                GetCurrentFilter(ref currentFilter);
                currentFilter.Save();

                cbFilters.SelectedItem = currentFilter;
            }
        }


        private void cbFilters_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_service.FiltersExist) SetFilter((Filter)((ComboBox)sender).SelectedItem);
        }

        private void btnOptions_Click(object sender, EventArgs e)
        {
            SettingsForm settingsForm = new SettingsForm(_service);
            settingsForm.ShowDialog();

            _service.TryFilters();
            LoadFilters();
            btnSave.Enabled = _service.FiltersExist;
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            DialogResult = System.Windows.Forms.DialogResult.Cancel;
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            SetFilter(null);
        }
    }

    internal class ItemComparer : IComparer
    {
        private int columnIndex = 0;
        private bool sortAscending = true;

        public int ColumnIndex
        {
            set
            {
                //предыдущий клик был на этой же колонке? 
                if (columnIndex == value)
                    //да - меняем направление сортировки 
                    sortAscending = !sortAscending;
                else
                {
                    columnIndex = value;
                    sortAscending = true;
                }
            }
        }

        #region Implementation of IComparer

        /// <summary>
        /// Сравнивает два объекта и возвращает значение, показывающее, что один объект меньше или больше другого или равен ему.
        /// </summary>
        /// <returns>
        /// Значение Условие Меньше нуля <paramref name="x"/> меньше, чем <paramref name="y"/>. Нуль <paramref name="x"/> равно <paramref name="y"/>. Больше нуля <paramref name="x"/> больше, чем <paramref name="y"/>. 
        /// </returns>
        /// <param name="x">Первый сравниваемый объект. </param><param name="y">Второй сравниваемый объект. </param><exception cref="T:System.ArgumentException">Ни параметр <paramref name="x"/>, ни параметр <paramref name="y"/> не реализует интерфейс <see cref="T:System.IComparable"/>.-или- 
        ///                 Параметры <paramref name="x"/> и <paramref name="y"/> имеют разные типы и не могут сравниваться друг с другом. </exception><filterpriority>2</filterpriority>
        public int Compare(object x, object y)
        {
            string value1 = ((ListViewItem)x).SubItems[columnIndex].Text;
            string value2 = ((ListViewItem)y).SubItems[columnIndex].Text;

            if (columnIndex == 1) //ID
            {
                short numValue1 = Convert.ToInt16(value1);
                short numValue2 = Convert.ToInt16(value2);

                return (numValue1 - numValue2) * (sortAscending ? 1 : -1);
            }

            if (columnIndex == 6) //DueDate
            {
                DateTime dateValue1 = Convert.ToDateTime(value1);
                DateTime dateValue2 = Convert.ToDateTime(value2);

                return DateTime.Compare(dateValue1,dateValue2) * (sortAscending ? 1 : -1);
            }

            return String.Compare(value1, value2) * (sortAscending ? 1 : -1);
        }

        #endregion
    }
}
